﻿/**
 *	\file		lxpref_route_end.cxx
 *	\date		(2015-01-01 00:38:39)/(2015-01-01 00:38:39)
 *-----------------------------------------------------------------------------
 *	\brief
 *	\version	1.0.0.1
 *	\author		Nick Shallery	(nicknide@gmail.com)
 *	\copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#include	"./lxpref_route_end.hxx"
#include	"./lxpref_route_clt_usr.hxx"
#include	"./lxpref_route_msg.hxx"

#include	"../lxsamsara/recurrence.h"

#include	<lxnet/lxnet_itf.h>

#include	<lolix/toy/stdc_fun.h>
#include	<lolix/loli/critical_section.h>

#include	<lxut/ctrl/ctrl_string.h>

#include	<lolix/toy/archive.hpp>
#define		LOLIX_DEF__MEMORY_FILE_STREAM
#include	<lolix/toy/archive_file_filter.hpp>

lxpref::_inst::lxpref_route_end_inst::lxpref_route_end_inst(lolix::loli::signal* sign, lolix::dynamic_allocator* alc)
	: _net_conn(0)
	, _dat(sign, alc)
	, _evt_inf(0)
	, _name_map(lolix::toy::less(), alc)
{
}


lxpref::_inst::lxpref_route_end_inst::~lxpref_route_end_inst(void)
{
	this->_Unlink();
	this->_recur->release();
	this->_signal->release();
	_str_fmt->release();
	_net_fac->release();
	_cs->release();
	_stdc->release();
	_alc->release();
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::create_inst(this_type** out_ptr
	, lolix::dynamic_allocator* alc
	, lolix::ref_factory* ref_fac
	, lxnet::net_factory* net_fac
	, lolix::toy::stdc_fun* stdc
	, lxsamsara::recurrence* recur
	, lolix::loli::signal::factory_type* sig_fac
	, lolix::loli::critical_section_factory* cs_fac
	, lxut::ctrl::ctrl_string_factory* ctrl_str_fac
	, lolix::lx_wchar const* path
	, lolix::size_type path_len
	, lxio::file_async_pool* async_pool
	)
{
	lolix::loli::signal* sig;
	LOLIX_RETNV rtv;
	if ( LOLIX_CHECK_ERROR(rtv = sig_fac->create_inst(&sig, false)) )
		return rtv;
	atexit_release(*sig);

	lxut::ctrl::ctrl_string* str_fmt;
	if ( LOLIX_CHECK_ERROR(rtv = ctrl_str_fac->create_inst(&str_fmt, L"unknow_string_{0}", 17, true)) )
		return rtv;
	atexit_release(*str_fmt);

	lolix::loli::critical_section* cs;
	if ( LOLIX_CHECK_ERROR(rtv = cs_fac->create_inst(&cs LOLIX_CS_MARK_NAME_P(L"lxpref::_inst::lxpref_route_end_inst::_cs"))) )
		return rtv;
	atexit_release(*cs);

	this_type* ptr;
	if ( LOLIX_CHECK_ERROR(rtv = __Create_inst_set_alc(&ptr, alc, ref_fac, sig, alc)) )
		return rtv;
	atexit_release(*ptr);

	(ptr->_str_fmt = str_fmt)->inc_ref();
	(ptr->_net_fac = net_fac)->inc_ref();
	(ptr->_signal = sig)->inc_ref();
	(ptr->_stdc = stdc)->inc_ref();
	(ptr->_cs = cs)->inc_ref();
	(ptr->_recur = recur)->inc_ref();
	if ( LOLIX_CHECK_ERROR(rtv = ptr->_Link(path, path_len, async_pool)) )
		return rtv;
	(*out_ptr = ptr)->inc_ref();
	return rtv;
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::close(void)
{
	return this->_Unlink();
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::wait(lolix::toy::time_span const* wait_ts)const
{
	return _signal->wait(wait_ts);
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::top(event_info const** evt_inf)
{
	if ( !_evt_inf )
	{
		_evt_inf = this->_dat.peek();
		if ( !_evt_inf )
		{
			*evt_inf = 0;
			return lolix::LOLIX_INFO_LOST_SYNC;
		}
	}
	*evt_inf = _evt_inf;
	return lolix::LOLIX_RETNV_OK;
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::fetch(event_info const* evt_inf)
{
	if ( !evt_inf )
		return lolix::LOLIX_ERROR_INVALID_RESOURCE;

	LOLIX_ASSERT(evt_inf == this->_evt_inf, L"还回的指针不一致");
	this->_dat.free(this->_evt_inf);
	this->_evt_inf = 0;
	return lolix::LOLIX_RETNV_OK;
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::_Link(lolix::lx_wchar const* path, lolix::size_type path_len, lxio::file_async_pool* async_pool)
{
	lolix::loli::file::open_flag of;
	of.mark_async_read();
	of.operat_write = 1;
	of.type_mask = of.create_new;
	lxnet::net_connect* net_conn;
	LOLIX_RETNV rtv;
	if ( LOLIX_CHECK_ERROR(rtv = _net_fac->query_connect(&net_conn, path, path_len, of, async_pool)) )
		return rtv;
	atexit_release(*net_conn);
	if ( LOLIX_CHECK_ERROR(rtv = this->_Unlink()) )
		return rtv;
	lolix::loli::file_async* fa;
	if ( LOLIX_CHECK_ERROR(rtv = net_conn->query_itf(&fa)) )
		return rtv;
	atexit_release(*fa);

	clt_usr* cusr;
	if ( LOLIX_CHECK_ERROR(rtv = clt_usr::create_inst(&cusr, _alc, 0, _stdc, fa, _recur)) )
		return rtv;
	atexit_release(*cusr);

	void* buf;
	size_type buf_size;
	cusr->_get_recv_buf(&buf, &buf_size);
	if ( LOLIX_CHECK_ERROR(rtv = fa->read(0, 0, buf_size, buf, cusr, this, &lxpref_route_end_inst::_On_read)) )
		return rtv;
	cusr->inc_ref();
	this->inc_ref();
	(this->_net_conn = net_conn)->inc_ref();
	return rtv;
}


lolix::LOLIX_RETNV
lxpref::_inst::lxpref_route_end_inst::_Unlink(void)
{
	event_info* evt_inf = lolix::imp::lock_chg(&this->_evt_inf, 0);
	if ( evt_inf )
		this->_dat.free(evt_inf);
	lxnet::net_connect* net_conn = lolix::imp::lock_chg(&this->_net_conn, 0);
	if ( !net_conn )
		return lolix::LOLIX_INFO_REOPERATOR;
	atexit_release(*net_conn);
	net_conn->close();
	return lolix::LOLIX_RETNV_OK;
}


void
lxpref::_inst::lxpref_route_end_inst::_On_read(lolix::loli::file_async_result* fas)
{
	clt_usr* usr = static_cast<clt_usr*>(fas->usr_dat());
	lolix::loli::file_async* fa = usr->_get_file_async();
	LOLIX_DEF__ENTER_SECTION();
	lolix::LOLIX_RETNV rtv;
	void* buf;
	size_type buf_size;
	if ( LOLIX_CHECK_ERROR(rtv = fas->get_result(&buf, &buf_size)) || buf_size == 0 )
		break;
	usr->_do_recv(buf_size, &this_type::_On_recvPack_s, this);
	usr->_get_recv_buf(&buf, &buf_size);
	if ( LOLIX_CHECK_ERROR(rtv = fa->read(0, 0, buf_size, buf, usr, this, &this_type::_On_read)) )
		break;
	return;
	LOLIX_DEF__LEAVE_SECTION();

	this->_Unlink();
	usr->release();
	this->release();
	fa->close();
}


void
lxpref::_inst::lxpref_route_end_inst::_On_recvPack_s(clt_usr* cusr, message::PREF_MSG_TYPE msgType, void const* buf, lolix::size_type buf_size, void* usr_ptr)
{
	this_type* ptr = static_cast<this_type*>(usr_ptr);
	ptr->_On_recvPack(cusr, msgType, buf, buf_size);
}


void
lxpref::_inst::lxpref_route_end_inst::_On_recvPack(clt_usr* cusr, message::PREF_MSG_TYPE msgType, void const* buf, lolix::size_type buf_size)
{
	lolix::loli::memory_file_stream<allocator_type> mem_file(_stdc, _alc);
	mem_file.write(buf, &buf_size);
	mem_file.seek_to(0);
	lolix::toy::archive_no_throw arc(&mem_file);
	switch ( msgType )
	{
	case message::MSG_TYPE_INFO:
		{
			lxpref::event_info pref_info;
			arc >> pref_info;
			//event_info evt_inf;
			//pref_info.copy_to(&evt_inf);

			message::query_names<allocator_type> unknows(_alc);
			{
				bind_invoke(*_cs, enter(), leave());
				for ( size_type i = 0; i != pref_info.param_cnt; ++i )
				{
					ptrdiff_t pos = (ptrdiff_t)pref_info.str_param[i];
					auto iter = this->_name_map.find(pos);
					if ( iter == this->_name_map.end() )
					{
						//	Create New String
						this->_str_fmt->replace(0, pos);
						lolix::lx_wchar const* str;
						lolix::size_type str_len = this->_str_fmt->result(&str);
						auto ist_ret = this->_name_map.insert(lolix::toy::make_pair(pos, _TWstring(_alc)));
						ist_ret.first->second.reserve(500);
						ist_ret.first->second.assign(str, str + str_len);
						unknows.names_address.push_back(pos);
						iter = ist_ret.first;
					}
					pref_info.str_param[i] = iter->second.c_str();
				}
			}

			this->_dat.push(pref_info);
			if ( !unknows.names_address.empty() )
			{
				mem_file.seek_to(0);
				arc << unknows;

				message::packet_header<allocator_type> pheader(_alc);
				lolix::lx_i64 cur_pos = 0;
				mem_file.seek(&cur_pos, 1);
				mem_file.swap_datas(pheader.dat, 0);
				pheader.dat.resize((size_type)cur_pos);
				pheader.msg_type = message::MSG_TYPE_QUERY_NAME;
				mem_file.seek_to(0);
				arc << pheader;
				cur_pos = 0;
				mem_file.seek(&cur_pos, 1);
				lolix::loli::file_async* fasync = cusr->_get_file_async();
				fasync->write(0, 0, (size_type)cur_pos, mem_file.dates(), 0, 0);
			}
		}
		break;

	case message::MSG_TYPE_QUEST_NAME:
		{
			message::response_names<allocator_type> names(_alc);
			arc >> names;
			bind_invoke(*_cs, enter(), leave());
			for ( size_type i = 0; i != names.name_ptr.size(); ++i )
			{
				lolix::ptrdiff_type ptrdiff = names.name_ptr[0];
				lolix::lx_wchar const* start = &names.names[names.name_idx[i]];
				auto res = this->_name_map.find(ptrdiff);
				if ( res == this->_name_map.end() )
				{
					this->_name_map.insert(lolix::toy::make_pair(ptrdiff, _TWstring(start, start + (size_type)names.name_len[i], _alc)));
					continue;
				}
				lolix::size_type buf_len = res->second.capacity();
				if ( names.name_len[i] < buf_len )
					buf_len = names.name_len[i];
				res->second.assign(start, start + buf_len);
			}
		}
		break;
	}
}
